package generation;

import java.util.Random;

public class Mutation {
	private int availableSpace;
	private String keyWord;
	private String currentPassword;
	
	/**
	 * create a new Mutation for the given keyword, with a certain available space.
	 * Warning : availableSpace must be positive.
	 */
	public Mutation (String keyWord, int availableSpace) {
		this.keyWord = keyWord;
		this.availableSpace = availableSpace;	
		this.currentPassword = "";
	}	
	
	//apply all the mution contains un mutationList to our current password
	public String applyMutation(String mutationList) {
		String[] mutationListSplit = mutationList.split(" ");
		currentPassword = this.keyWord;
		for(int i = 0; i < mutationListSplit.length; i++) {
			currentPassword = passwordMutation(Integer.parseInt(mutationListSplit[i]));
		}
		return currentPassword;
	}
	
	//realise the mutation depending on the mutId
	private String passwordMutation(int mutId) {
		switch(mutId) {
		case 0:
			//symbol
			return mutation("[aeiosu]",1);
		case 1:
			//min/maj
			return mutation("[a-z]", 2);
		case 2:
			//leet
			return mutation("[aehlnost]", 3);
		case 3:
			return prefSuffMutation();
		case 4:
		default:
			return currentPassword;

		}
	}

	private String changeLetter(String word, int letterPosition, String letter) {
		return (word.substring(0, letterPosition)+letter+word.substring(letterPosition+1, word.length()));
	}

	/**
	 * apply a mutation to the current password. The mutation is realiszed if the letter is in the regex, with 
	 * the methode given in idMethode : 1 for symbol
	 * 									2 for uperCase
	 * 									3 for leet 
	**/
	private String mutation(String regex, int idMethode) {
		Random randPosition = new Random();
		int oriPosition = randPosition.nextInt(currentPassword.length());
		String decomposePassword = currentPassword.substring(oriPosition, oriPosition+1);

		//we look first at the random position, then if it not match, we look around the original random position until
		// it match symbolRegex. If it's impossible, the word remain unchange.
		int e = 0;
		while( (e+oriPosition) < currentPassword.length() || (oriPosition - e) > 0 ) {

			//look the letter after
			int positionSup = oriPosition + e;
			if(positionSup < currentPassword.length()) {
				decomposePassword = currentPassword.substring(positionSup,positionSup+1);
				if(decomposePassword.matches(regex)) {
					switch(idMethode) {
					case 1:
						return (changeLetter(currentPassword,positionSup,symbolChange(decomposePassword)));
					case 2:
						return (changeLetter(currentPassword,positionSup,decomposePassword.toUpperCase()));
					case 3:
						return (changeLetter(currentPassword,positionSup,leetChange(decomposePassword)));
					}
				}
			}

			//look the letter before
			int positionLow = oriPosition - e;
			if(positionLow >= 0) {
				decomposePassword = currentPassword.substring(positionLow,positionLow+1);
				if(decomposePassword.matches(regex)) {
					switch(idMethode) {
					case 1:
						return (changeLetter(currentPassword,positionLow,symbolChange(decomposePassword)));
					case 2:
						return (changeLetter(currentPassword,positionLow,decomposePassword.toUpperCase()));
					case 3:
						return (changeLetter(currentPassword,positionLow,leetChange(decomposePassword)));
					}
				}
			}
			e++;
		}
		//if any letter in the password match symbolRegex, no changes are made
		return currentPassword;
	}

	private String prefSuffMutation() {
		Random randPref = new Random();
		boolean addPref = randPref.nextBoolean();
		//randomly choose if prefix or suffix
		if(addPref) {
			return (generateSymbol()+currentPassword);
		}
		return (currentPassword+generateSymbol());
	}

	//add a prefix or a suffix compose of one symbol and a number between 0 and 99.
	private String generateSymbol() {
		String symbols = "";
		Random rand = new Random();
		int randSymbol = rand.nextInt(10);

		switch(randSymbol) {
		case 0:
			symbols += "&";
			break;
		case 1:
			symbols += "*";
			break;
		case 2:
			symbols += "�";
			break;
		case 3:
			symbols += "�";
			break;
		case 4:
			symbols += "�";
			break;
		case 5:
			symbols += "#";
			break;
		case 6:
			symbols += "%";
			break;
		case 7:
			symbols += "";
			break;
		case 8:
			symbols += "";
			break;
		case 9:
		default:
			symbols += "";
			break;
		}

		int randValue = rand.nextInt(100);
		symbols += randValue;

		if(availableSpace >= symbols.length()){
			availableSpace -= symbols.length();
			return symbols;
		}
		else {
			int tempSpace = availableSpace;
			availableSpace = 0;
			return symbols.substring(0, tempSpace);
		}
	}

	//realise a symbol change for the letter decomposePassword
	private String symbolChange(String decomposePassword) {
		if(decomposePassword.equals("a")) {
			return ("@");			
		}
		if(decomposePassword.equals("o")) {
			return ("�");			
		}
		if(decomposePassword.equals("i")) {
			return ("�");			
		}
		if(decomposePassword.equals("s")) {
			return ("$");			
		}
		if(decomposePassword.equals("u")) {
			return ("�");			
		}
		if(decomposePassword.equals("e")) {
			return ("�");			
		}
		return decomposePassword;
	}

	//realize a leet change for the letter decomposePassword
	private String leetChange(String decomposePassword) {
		if(decomposePassword.equals("n") && availableSpace >= 2) {
			availableSpace -= 2;
			return ("|\\|");			
		}
		if(decomposePassword.equals("o")) {
			return ("0");			
		}
		if(decomposePassword.equals("l")) {
			return ("1");			
		}
		if(decomposePassword.equals("a")) {
			return ("4");			
		}
		if(decomposePassword.equals("e")) {
			return ("3");			
		}
		if(decomposePassword.equals("t")) {
			return ("7");			
		}
		if(decomposePassword.equals("h") && availableSpace >= 2) {
			availableSpace -= 2;
			return ("|-|");			
		}
		if(decomposePassword.equals("s") && availableSpace >= 2) {
			return ("5");			
		}
		return decomposePassword;
	}
}
